import type { AxiosResponse } from 'axios'
import { Toast } from 'vant'
import { errorResult, VAxios } from './Axios'
import { RequestMethodEnum, ServerTypeEnum } from './enums'
import { AxiosTransform, CreateAxiosOptions, RequestOptions, Result, GTAxiosOptions } from './types'
import { Sensors } from '../utils/sensors'
import { isObject, isString } from '../utils/is'
import { GTRequestInterface } from './personnel/types'
import { FQrequest, YJrequest, ZKrequest } from './personnel'
import { LoginLocalStorageKey } from '@/lib/js/hooks'
let { baseUrl } = process.env
if (process.env.APP_ENV === 'production') {
  baseUrl = window.location.origin.replace(/www/g, 'api')
}
const ErrorSystemMessage = '系统错误、请稍后尝试！'

let axiosOptions: GTAxiosOptions = {
  serverType: ServerTypeEnum.old
}

let requestHandler: GTRequestInterface

/*
* 合并对象
* */
function deepMerge<T = any>(src: any, target: any): T {
  Object.entries(target).forEach(([key, item]) => {
    src[key] = isObject(item) ? deepMerge(item, target[key]) : (src[key] = target[key])
  })
  return src
}

/*
* 请求钩子函数
* */
const transform: AxiosTransform = {
  /*
  *
  * */
  transformResponse: (res: AxiosResponse<Result>, options: RequestOptions) => {
    const { isTransformResponse } = options
    // 不进行任何处理，直接返回
    // 用于页面代码可能需要直接获取code，data，message这些信息时开启
    if (!isTransformResponse) {
      return res.data
    }
    // 错误的时候返回

    const { data: $data } = res
    if (!$data) {
      return errorResult
    }

    // 服务器返回接口格式
    if (!requestHandler.isSuccess($data)) {
      requestHandler.commonFail($data)
      return errorResult
    }

    // 接口请求成功
    const { data } = $data
    return data
  },

  /*
  * 请求之前处理config
  * */
  beforeRequestHook: (config, options) => {
    // options可以定义额外config数据处理规则
    const { ignoreCancelToken, isNeedToken } = options
    if (ignoreCancelToken) {
      config.headers = { ...config.headers, ignoreCancelToken }
    }
    if (config.method?.toUpperCase() === RequestMethodEnum.GET) { // 给 get 请求加上时间戳参数，避免从缓存中拿数据。
      const now = new Date().getTime()
      const $isString: boolean = isString(config.params)
      if (!$isString) {
        config.data = {
          params: Object.assign(config.params || {}, {
            _t: now
          })
        }
      } else { // 兼容字符串
        config.url = `${config.url + config.params}?_t=${now}`
        config.params = undefined
      }
    }

    if (isNeedToken) {
      requestHandler.addTokenToRequest(config, options)
    }

    return config
  },

  /*
  * 请求拦截器处理
  * */
  requestInterceptors: config => {
    const { url, method } = config
    Sensors.collectLog({
      id: 'ajaxRequest',
      data: { url, method }
    })
    return config
  },

  /*
  * 请求错误
  * */
  requestInterceptorsCatch: (error: any) => {
    const { message, config = {} } = error
    const { url, method, timeout } = config
    Sensors.pageError({
      id: 'ajax',
      type: 'request',
      data: { url, method, message, timeout }
    })
    return Promise.reject(error)
  },

  // responseInterceptors: (res: AxiosResponse<any>) => {
  //   //const { url, method, timeout } = config

  //   const { config : { url }, data } = res
  //   //console.log(config, data, res, '-----res')
  //   const Usinfo = localStorage.getItem('Us_info___')

  //   Sensors.collectLog({
  //     id: 'ajaxResponse',
  //     data: { url, data, Usinfo }
  //   })

  //   // /console.log({ url, data, Usinfo })

  //   return res
  // },
  /*
  * 响应错误处理
  * */
  responseInterceptorsCatch: (error: any) => {
    const { response, code, message, config = {} } = error || {}
    const msg: string = response?.data?.error ? response.data.error.message : ''
    const err: string = error?.toString()
    try {
      if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
        // 错误处理
        console.log('超时')
      }
      if (err?.includes('Network Error')) {
        // 错误处理
        Toast.fail(ErrorSystemMessage)
        console.log('错误处理')
      }
    } catch (error) {
      Toast.fail(ErrorSystemMessage)
      console.log('错误处理')
      throw new Error(error)
    }

    const status = error?.response?.status
    switch (status) {
      case 400:
        // 400 错误提示
        console.log(msg)
        break

      case 500:
        console.log('-----------500')
        break

      default:
    }
    const { url, method, timeout } = config
    Sensors.pageError({
      id: 'ajax',
      type: 'response',
      data: { msg, err, url, method, timeout }
    })
    return Promise.reject(error)
  }
}

function createAxios(opt?: Partial<CreateAxiosOptions>) {
  return new VAxios(deepMerge({
    baseURL: baseUrl,
    withCredentials: true,
    headers: {
      'Cache-Control': 'no-cache'
    },
    timeout: 30 * 1000,
    transform,
    requestOptions: {
      isTransformResponse: true,
      errorMessageMode: 'message',
      isNeedToken: true
    }
  }, opt || {}))
}

/*
*
* 预置Axios配置
*
**/
export const setupAxios = (ops: Partial<GTAxiosOptions> = {}) => {
  axiosOptions = { ...axiosOptions, ...ops }
  const { serverType } = axiosOptions
  if (serverType === ServerTypeEnum.new) {
    requestHandler = new FQrequest(axiosOptions)
  } else if (serverType === ServerTypeEnum.old) {
    requestHandler = new YJrequest(axiosOptions)
  } else if (serverType === ServerTypeEnum.zhangkai) {
    requestHandler = new ZKrequest(axiosOptions)
  }

}

/*
* 获取当前服务器使用
* */
export const getServerType = (): ServerTypeEnum => axiosOptions.serverType

// 逐渐优化掉
export const defHttp = createAxios()

export const axios = createAxios()

export const request = {

  get: function (url: string, data?: any, options = {}) {
    return axios.request({
      url,
      method: RequestMethodEnum.GET,
      params: data
    }, {
      ...options
    })
  },

  post: function (url: string, data?: any, options = {}) {
    return axios.request({
      url,
      method: RequestMethodEnum.POST,
      data
    }, {
      ...options
    })
  },

  formPost: function (url: string, data?: any, options = {}) {
    return axios.request({
      url,
      headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
      method: RequestMethodEnum.POST,
      data
    }, {
      ...options
    })
  },

  /**
   * 
   * @param url eg: /api/v9/annualbill2021/user/info
   */
  authUrl: function (url: string) {
    const key = encodeURIComponent(localStorage.getItem(LoginLocalStorageKey.key) || '')
    const signature = encodeURIComponent(localStorage.getItem(LoginLocalStorageKey.signature) || '')
    let nextUrl = ''
    // eg : `/api/v9/annualbill2021/user/info?key=${key}`
    nextUrl = `${url}?key=${key}`
    if (signature && signature !== 'null') {
      nextUrl += `&signature=${signature}`
    }

    return nextUrl;
  }

}
